home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / faxd / EverexRecv.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  15KB  |  577 lines

  1. /*    $Header: /usr/people/sam/fax/faxd/RCS/EverexRecv.c++,v 1.52 1994/04/08 03:49:33 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include <stdio.h>
  26. #include <time.h>
  27. #include "Everex.h"
  28. #include "ModemConfig.h"
  29.  
  30. #include "t.30.h"
  31. #include "everex.h"
  32. #include <stdlib.h>
  33.  
  34. /*
  35.  * Recv Protocol for Class-1-style Everex modems.
  36.  */
  37.  
  38. #define    FAX_RECVMODE    (S2_HOSTCTL|S2_PADEOLS|S2_19200)
  39.  
  40. CallType
  41. EverexModem::answerCall(AnswerType atype, fxStr& emsg)
  42. {
  43.     if (atype == FaxModem::ANSTYPE_FAX || atype == FaxModem::ANSTYPE_ANY) {
  44.     if (!atCmd("#A#S8=8#S9=45V1&E1S0=0X4"))
  45.         goto bad;
  46.     if (!modemFaxConfigure(FAX_RECVMODE|S2_RESET))
  47.         goto bad;
  48.     if (!setupFrame(FCF_DIS|FCF_RCVR, modemDIS()))
  49.         goto bad;
  50.     if (!setupFrame(FCF_CSI|FCF_RCVR, (char*) lid))
  51.         goto bad;
  52.     if (!atCmd("#T2100=30")) {
  53.     bad:
  54.         emsg = "Unspecified Receive Phase B error";
  55.         return (CALLTYPE_ERROR);
  56.     } else
  57.         return (CALLTYPE_FAX);
  58.     }
  59.     return (FaxModem::answerCall(atype, emsg));
  60. }
  61.  
  62. fxBool
  63. EverexModem::recvBegin(fxStr& emsg)
  64. {
  65.     setInputBuffering(FALSE);
  66.     prevPage = FALSE;                // no previous page received
  67.     pageGood = FALSE;                // quality of received page
  68.     return recvIdentification(FCF_CSI|FCF_RCVR, FCF_DIS|FCF_RCVR, emsg);
  69. }
  70.  
  71. /*
  72.  * Transmit DIS/DTC and wait for a response.
  73.  */
  74. fxBool
  75. EverexModem::recvIdentification(u_int f1, u_int f2, fxStr& emsg)
  76. {
  77.     u_int t1 = howmany(conf.t1Timer, 1000);    // T1 in seconds
  78.     time_t start = time(0);
  79.     emsg = "No answer (T.30 T1 timeout)";
  80.     do {
  81.     /*
  82.      * Transmit (NSF) (CSI) DIS frames when the receiving
  83.      * station or (NSC) (CIG) DTC when initiating a poll.
  84.      */
  85.     if (sendFrame(f1, f2)) {
  86.         /*
  87.          * Wait for a response to be received.
  88.          */
  89.         if (recvFrame(conf.t2Timer)) {    // XXX should be TIMER_T4
  90.         do {
  91.             /*
  92.              * Verify a DCS command response and, if
  93.              * all is correct, receive phasing/training.
  94.              */
  95.             u_int fcf;
  96.             if (!recvDCSFrames(rbuf+2, fcf)) {
  97.             fcf &= ~FCF_SNDR;
  98.             if (fcf == FCF_DCN)
  99.                 emsg = "RSPREC error/got DCN";
  100.             else            // XXX DTC/DIS not handled
  101.                 emsg = "RSPREC invalid response received";
  102.             break;
  103.             }
  104.             if (recvTraining())
  105.             return (TRUE);
  106.             emsg = "Failure to train modems";
  107.         } while (recvFrame(conf.t2Timer));
  108.         }
  109.     }
  110.     /*
  111.      * If we failed to send our frames or failed to
  112.      * receive DCS from the other side, then delay
  113.      * long enough to miss any training that the other
  114.      * side might have sent us.  Otherwise the caller
  115.      * will miss our retransmission since it'll be
  116.      * in the process of sending training.
  117.      */
  118.     pause(conf.class1TrainingRecovery);
  119.     } while (time(0)-start < t1);
  120.     return (FALSE);
  121. }
  122.  
  123. fxBool
  124. EverexModem::recvDCSFrames(const char* cp, u_int& fcf)
  125. {
  126.     for (; *cp; cp += 3) {
  127.     fcf = fromHex(cp, 2);
  128.     switch (fcf) {
  129.     case FCF_NSS|FCF_SNDR:
  130.         (void) recvNSS();
  131.         break;
  132.     case FCF_DCS|FCF_SNDR:
  133.         (void) recvDCS();
  134.         break;
  135.     case FCF_TSI|FCF_SNDR:
  136.         (void) recvTSI();
  137.         break;
  138.     case FCF_CRP:        // resend last frame
  139.         break;
  140.     }
  141.     }
  142.     return (fcf == (FCF_DCS|FCF_SNDR));
  143. }
  144.  
  145. /*
  146.  * Wait-for and decode training response.
  147.  */
  148. fxBool
  149. EverexModem::recvTraining()
  150. {
  151.     protoTrace("RECV training");
  152.     startTimeout(conf.t1Timer);
  153.     char buf[1024];
  154.     while (getModemLine(buf, sizeof (buf)) > 2 && !strneq(buf, "M ", 2))
  155.     ;
  156.     stopTimeout("reading from modem");
  157.     pause(conf.class1TCFResponseDelay);    // delay between carrier switch
  158.     fxBool ok = (!wasTimeout() && strneq(buf, "M 3", 3));
  159.     if (ok) {
  160.     sendFrame(FCF_CFR|FCF_RCVR);
  161.     protoTrace("TRAINING succeeded");
  162.     } else {
  163.     sendFrame(FCF_FTT|FCF_RCVR);
  164.     protoTrace("TRAINING failed");
  165.     }
  166.     return (ok);
  167. }
  168.  
  169. /*
  170.  * Decode a received TSI and ask the server if
  171.  * we should accept documents from the client.
  172.  */
  173. fxBool
  174. EverexModem::recvTSI()
  175. {
  176.     if (atCmd("#FRC2?", AT_NOTHING)) {
  177.     char buf[1024];
  178.     int n = getModemLine(buf, sizeof (buf));
  179.     if (sync()) {
  180.         fxStr tsi;
  181.         if (n > 2)
  182.         decodeCSI(tsi, fxStr(buf, n));
  183.         (void) recvCheckTSI(tsi);
  184.         return (TRUE);
  185.     }
  186.     }
  187.     return (FALSE);
  188. }
  189.  
  190. /*
  191.  * Decode and process a received DCS.
  192.  */
  193. fxBool
  194. EverexModem::recvDCS()
  195. {
  196.     if (atCmd("#FRC1?", AT_NOTHING)) {
  197.     char buf[1024];
  198.     int n = getModemLine(buf, sizeof (buf));
  199.     if (sync() && n >= 6) {
  200.         u_int dcs = fromHex(buf, fxmin(n,6));
  201.         u_int xinfo =
  202.         ((dcs & DCS_XTNDFIELD) && n >= 8 ? fromHex(buf+6, 2) : 0);
  203.         Class2Params params;
  204.         params.setFromDCS(dcs, xinfo);
  205.         is2D = (params.df >= DF_2DMR);        // NB: assumes no G4
  206.         setDataTimeout(60, params.br);
  207.         FaxModem::recvDCS(params);
  208.         return (TRUE);
  209.     }
  210.     }
  211.     return (FALSE);
  212. }
  213.  
  214. /*
  215.  * Process a received NSS.
  216.  */
  217. fxBool
  218. EverexModem::recvNSS()
  219. {
  220.     if (atCmd("#FRC4?", AT_NOTHING)) {
  221.     char buf[1024];
  222.     int n = getModemLine(buf, sizeof (buf));
  223.     if (sync()) {
  224.         protoTrace("REMOTE NSS \"%s\"", buf);
  225.         return (TRUE);
  226.     }
  227.     }
  228.     return (FALSE);
  229. }
  230.  
  231. const u_int EverexModem::modemPPMCodes[8] = {
  232.     0,            // 0
  233.     PPM_EOM,        // FCF_EOM+FCF_PRI_EOM
  234.     PPM_MPS,        // FCF_MPS+FCF_PRI_MPS
  235.     0,            // 3
  236.     PPM_EOP,        // FCF_EOP+FCF_PRI_EOP
  237.     0,            // 5
  238.     0,            // 6
  239.     0,            // 7
  240. };
  241.  
  242. /*
  243.  * Receive a page of data.
  244.  */
  245. fxBool
  246. EverexModem::recvPage(TIFF* tif, int& ppm, fxStr& emsg)
  247. {
  248.     fxBool messageReceived = FALSE;
  249.     while (getModemLine(rbuf, sizeof (rbuf), conf.t1Timer) >= 3) {
  250.     if (strneq(rbuf, "M 1", 3)) {        // message carrier received
  251.         /*
  252.          * Message carrier received; receive page.
  253.          */
  254.         setInputBuffering(TRUE);
  255.         protoTrace("RECV: begin page");
  256.         (void) atCmd("#P7");        // switch to high speed carrier
  257.         u_int br = (FAX_RECVMODE & S2_9600 ? BR9600 : BR19200);
  258.         if (setBaudRate(br, FLOW_NONE, FLOW_XONXOFF)) {
  259.         recvSetupPage(tif, GROUP3OPT_FILLBITS, FILLORDER_LSB2MSB);
  260.         pageGood = recvPageData(tif, emsg);
  261.         (void) sendBreak(FALSE);    // back to low speed
  262.         (void) setBaudRate(EVEREX_CMDBRATE, FLOW_XONXOFF, FLOW_XONXOFF);
  263.         protoTrace("RECV: end page");
  264.         if (wasTimeout()) {
  265.             setInputBuffering(FALSE);
  266.             return (FALSE);
  267.         }
  268.         /*
  269.          * The data was received correctly, wait
  270.          * for the modem to signal carrier drop.
  271.          */
  272.         messageReceived = waitFor(AT_OK);
  273.         setInputBuffering(FALSE);
  274.         if (!messageReceived)
  275.             return (FALSE);
  276.         prevPage = TRUE;
  277.         } else {
  278.         emsg = "Can not change baud rate for Phase C data";
  279.         (void) sendBreak(FALSE);    // back to low speed
  280.         }
  281.     } else if (strneq(rbuf, "R ", 2)) {    // HDLC frames received
  282.         /*
  283.          * Do <command received> logic.
  284.          */
  285.         u_int fcf = fromHex(rbuf+2, 2);
  286.         switch (fcf) {
  287.         case FCF_DTC:            // XXX no support
  288.         case FCF_DIS:            // XXX no support
  289.         protoTrace("RECV DIS/DTC");
  290.         emsg = "Can not continue after DIS/DTC";
  291.         return (FALSE);
  292.         case FCF_NSS|FCF_SNDR:
  293.         case FCF_TSI|FCF_SNDR:
  294.         case FCF_DCS|FCF_SNDR:
  295.         if (recvDCSFrames(rbuf+2, fcf))
  296.             (void) recvTraining();
  297.         messageReceived = FALSE;
  298.         break;
  299.         case FCF_MPS|FCF_SNDR:        // MPS
  300.         case FCF_EOM|FCF_SNDR:        // EOM
  301.         case FCF_EOP|FCF_SNDR:        // EOP
  302.         case FCF_PRI_MPS|FCF_SNDR:        // PRI-MPS
  303.         case FCF_PRI_EOM|FCF_SNDR:        // PRI-EOM
  304.         case FCF_PRI_EOP|FCF_SNDR:        // PRI-EOP
  305.         tracePPM("RECV recv", fcf);
  306.         if (!prevPage) {
  307.             /*
  308.              * Post page message, but no previous page
  309.              * was received--this violates the protocol.
  310.              */
  311.             emsg = "COMREC invalid response received";
  312.             return (FALSE);
  313.         }
  314.         /*
  315.          * [Re]transmit post page response.
  316.          */
  317.         if (pageGood) {
  318.             (void) sendFrame(FCF_MCF|FCF_RCVR);
  319.             tracePPR("RECV send", FCF_MCF);
  320.             /*
  321.              * If post page message confirms the page
  322.              * that we just received, write it to disk.
  323.              */
  324.             if (messageReceived) {
  325.             TIFFWriteDirectory(tif);
  326.             countPage();
  327.             ppm = modemPPMCodes[fcf&7];
  328.             return (TRUE);
  329.             }
  330.         } else {
  331.             /*
  332.              * Page not received, or unacceptable; tell
  333.              * other side to retransmit after retrain.
  334.              */
  335.             (void) sendFrame(FCF_RTN|FCF_RCVR);
  336.             tracePPR("RECV send", FCF_RTN);
  337.             messageReceived = FALSE;
  338.             /*
  339.              * Reset the TIFF-related state so that subsequent
  340.              * writes will overwrite the previous data.
  341.              */
  342.             recvResetPage(tif);
  343.         }
  344.         break;
  345.         case FCF_DCN|FCF_SNDR:        // DCN
  346.         tracePPM("RECV recv", fcf);
  347.         emsg = "COMREC received DCN";
  348.         return (FALSE);
  349.         default:
  350.         emsg = "COMREC invalid response received";
  351.         return (FALSE);
  352.         }
  353.     } else {
  354.         modemTrace("Unrecognized response \"%s\"", rbuf);
  355.         emsg = "Unrecognized response from modem";
  356.         return (FALSE);
  357.     }
  358.     }
  359.     emsg = "T.30 T2 timeout, expected page not received";
  360.     return (FALSE);
  361. }
  362.  
  363. static const int EOL = 0x001;        // end-of-line code (11 0's + 1)
  364.  
  365. #define    BITCASE(b)            \
  366.     case b:                \
  367.     c <<= 1;            \
  368.     if (shdata & b) c |= 1;        \
  369.     l++;                \
  370.     if (c > 0) { shbit = (b<<1); break; }
  371.  
  372. /*
  373.  * Receive a Huffman code.
  374.  */
  375. void
  376. EverexModem::recvCode(int& len, int& code)
  377. {
  378.     short c = 0;
  379.     short l = 0;
  380.     switch (shbit & 0xff) {
  381. again:
  382.     BITCASE(0x01);
  383.     BITCASE(0x02);
  384.     BITCASE(0x04);
  385.     BITCASE(0x08);
  386.     BITCASE(0x10);
  387.     BITCASE(0x20);
  388.     BITCASE(0x40);
  389.     BITCASE(0x80);
  390.     default:
  391.     shdata = getModemDataChar();
  392.     if (shdata == EOF)
  393.         longjmp(recvEOF, 1);
  394.     goto again;
  395.     }
  396.     code = c;
  397.     len = l;
  398. }
  399.  
  400. /*
  401.  * Return the next bit from the modem.
  402.  */
  403. int
  404. EverexModem::recvBit()
  405. {
  406.     if ((shbit & 0xff) == 0) {
  407.     shdata = getModemDataChar();
  408.     if (shdata == EOF)
  409.         longjmp(recvEOF, 1);
  410.     shbit = 0x01;
  411.     }
  412.     int b = (shdata & shbit) != 0;
  413.     shbit <<= 1;
  414.     return (b);
  415. }
  416.  
  417. /*
  418.  * Receive a page of G3-encoded data.  EOLs are counted and
  419.  * bad rows are replaced with a previous good rows received.
  420.  */
  421. fxBool
  422. EverexModem::recvPageData(TIFF* tif, fxStr& emsg)
  423. {
  424.     u_long badfaxrows = 0;        // # of rows w/ errors
  425.     int badfaxrun = 0;            // current run of bad rows
  426.     int    maxbadfaxrun = 0;        // longest bad run
  427.     u_char thisrow[howmany(2432,8)];    // current accumulated row
  428.     u_char lastrow[howmany(2432,8)];    // previous row for regeneration
  429.     int eols = 0;            // count of consecutive EOL codes
  430.     int lastlen = 0;            // length of last row received (bytes)
  431.     u_long row = 0;            // received row number
  432.     int tag = 0;            // 2D decoding tag that follows EOL
  433.     u_long totbytes = 0;        // total bytes of data received
  434.     u_char* ep = &thisrow[sizeof (thisrow)-2];
  435.  
  436.     if (setjmp(recvEOF) != 0) {
  437.     emsg = "Missing EOL after 5 seconds";
  438.     protoTrace("RECV: premature EOF, row %lu", row);
  439.     recvDone(tif, totbytes, row, badfaxrows, maxbadfaxrun);
  440.     return (FALSE);
  441.     }
  442. top:
  443.     u_char* cp = &thisrow[0];        // place to put next byte
  444.     int bit = 0x80;            // current bit of received data
  445.     int data = 0;            // current received data byte
  446.     fxBool emptyLine = TRUE;        // is current line empty?
  447.     /*
  448.      * The "2" here means that we treat 2 consecutive
  449.      * EOL codes (w/o intervening data) as RTC.  This
  450.      * is a cheat, but means that we don't hang if
  451.      * the RTC is chopped by the sender or the modem.
  452.      * Since the many other fax machines do this and
  453.      * the Class 2 spec says that it will always compress
  454.      * consecutive EOL codes to one, this should be ok.
  455.      */
  456.     while (eols < 2) {
  457.     int len, code;
  458.     recvCode(len, code);
  459.     if (len >= 12) {
  460.         if (code == EOL) {
  461.         /*
  462.          * Found an EOL, flush the current row and
  463.          * check for RTC (6 consecutive EOL codes).
  464.          */
  465.         if (is2D)
  466.             tag = recvBit();
  467.         if (!emptyLine) {
  468.             if (bit != 0x80)            // pad to byte boundary
  469.             *cp++ = data;
  470.             // insert EOL and tag bit if 2D
  471.             *cp++ = 0x00;
  472.             if (is2D)
  473.             *cp++ = 0x02|tag;
  474.             else
  475.             *cp++ = 0x01;
  476.             lastlen = cp - thisrow;
  477.             TIFFReverseBits(thisrow, lastlen);
  478.             TIFFWriteRawStrip(tif, 0, thisrow, lastlen);
  479.             memcpy(lastrow, thisrow, lastlen);    // save for regeneration
  480.             row++;
  481.             totbytes += lastlen;
  482.             eols = 0;
  483.         } else
  484.             eols++;
  485.         if (badfaxrun > maxbadfaxrun)
  486.             maxbadfaxrun = badfaxrun;
  487.         badfaxrun = 0;
  488.         goto top;
  489.         }
  490.         if (len > 13) {
  491.         /*
  492.          * Encountered a bogus code word; skip to the
  493.          * EOL and regenerate the previous line.   Note
  494.          * that for 2D data, the regeneration uses the
  495.          * last line, not the last 1D-encoded line--this
  496.          * is WRONG (we should also be careful about 2D
  497.          * lines that follow a regenerated line).
  498.          */
  499.         protoTrace("RECV: bad code word 0x%x, len %d, row %lu",
  500.             code, len, row);
  501.         badfaxrows++, badfaxrun++;
  502.         // skip input data to next EOL
  503.         do {
  504.             recvCode(len, code);
  505.         } while (len < 12 || code != EOL);
  506.         if (is2D)
  507.             tag = recvBit();
  508.         // regenerate previous row
  509.         TIFFWriteRawStrip(tif, 0, lastrow, lastlen);
  510.         goto top;
  511.         }
  512.     }
  513.     // shift code into scanline buffer (could unroll expand loop)
  514.     for (u_int mask = 1<<(len-1); mask; mask >>= 1) {
  515.         if (code & mask)
  516.         data |= bit;
  517.         if ((bit >>= 1) == 0) {
  518.         if (cp < ep)
  519.             *cp++ = data;
  520.         data = 0;
  521.         bit = 0x80;
  522.         }
  523.     }
  524.     emptyLine = FALSE;
  525.     }
  526.     recvDone(tif, totbytes, row, badfaxrows, maxbadfaxrun);
  527.     return (TRUE);        // XXX check copy quality
  528. }
  529.  
  530. /*
  531.  * Force image length and write data characterization tags.
  532.  */
  533. void
  534. EverexModem::recvDone(TIFF* tif, u_long totbytes, u_long nrows, u_long bad, int maxbad)
  535. {
  536.     protoTrace("RECV: %lu bytes, %lu rows", totbytes, nrows);
  537.     TIFFSetField(tif, TIFFTAG_IMAGELENGTH, nrows);
  538.     if (bad) {
  539.     TIFFSetField(tif, TIFFTAG_BADFAXLINES,    bad);
  540.     TIFFSetField(tif, TIFFTAG_CLEANFAXDATA,    CLEANFAXDATA_REGENERATED);
  541.     TIFFSetField(tif, TIFFTAG_CONSECUTIVEBADFAXLINES, maxbad);
  542.     } else
  543.     TIFFSetField(tif, TIFFTAG_CLEANFAXDATA,    CLEANFAXDATA_CLEAN);
  544. }
  545.  
  546. /*
  547.  * Complete a receive session.
  548.  */
  549. fxBool
  550. EverexModem::recvEnd(fxStr&)
  551. {
  552.     (void) recvFrame(conf.t2Timer);        // accept any DCN
  553.     u_int t1 = howmany(conf.t1Timer, 1000);    // T1 timer in seconds
  554.     time_t start = time(0);
  555.     /*
  556.      * Wait for DCN and retransmit ack of EOP if needed.
  557.      */
  558.     u_int fcf = FCF_EOP|FCF_SNDR;
  559.     do {
  560.     if (recvFrame(conf.t2Timer)) {
  561.         switch (fcf = fromHex(rbuf+2, 2)) {
  562.         case FCF_EOP|FCF_SNDR:
  563.         (void) sendFrame(FCF_MCF|FCF_RCVR);
  564.         tracePPM("RECV recv", FCF_EOP);
  565.         break;
  566.         case FCF_DCN|FCF_SNDR:
  567.         break;
  568.         default:
  569.         sendFrame(FCF_DCN|FCF_RCVR);
  570.         break;
  571.         }
  572.     }
  573.     } while (time(0)-start < t1 && fcf == (FCF_EOP|FCF_SNDR));
  574.     setInputBuffering(TRUE);
  575.     return (TRUE);
  576. }
  577.